//
// Created by fyt79 on 2019/4/22.
//
#include "psd.h"

void psd_begin_dtoa(unsigned int psd,unsigned int buf_count, unsigned int buf_size, short* i, short* q) {
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28) | MMIO_SB3500_BASE_ADDR;
  unsigned control;
  volatile unsigned * d2a;
  volatile unsigned * en;
  switch (psd) {
    case PSD_A:
      d2a = (volatile unsigned *)(mmio|MMIO_SB3500D2A_A_OFF);
      en  = (volatile unsigned  *)(mmio|MMIO_SB3500PSDA_EN);
      break;
    case PSD_B:
      d2a = (volatile unsigned *)(mmio|MMIO_SB3500D2A_B_OFF);
      en  = (volatile unsigned  *)(mmio|MMIO_SB3500PSDB_EN);
      break;
    default:
      return;
  }
  control = (3<<30)              /* enable both I,Q */
            | (1<<28)                    /* direction */
            | (((buf_count-1)&0xff)<<20)     /* buffers         */
            | ((0&0x3)<<18)              /* no PM timer        */
            | ((0&0x7)<<15)              /* no NMPT timer        */
            | ((buf_size-8)&0x7ff8);       /* bytes truncated to multiple of 8 */
  d2a[2] = (unsigned)i;
  d2a[4] = (unsigned)q;
  d2a[6] = control;
  en[0]  = 0x2;                   /* enable D2A */
}

void psd_stop_dtoa(unsigned int psd) {
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28) | MMIO_SB3500_BASE_ADDR;
  volatile unsigned *d2a;
  volatile unsigned *en;
  volatile unsigned *status;
  switch (psd) {
    case PSD_A:
      d2a = (volatile unsigned *)(mmio|MMIO_SB3500D2A_A_OFF);
      en  = (volatile unsigned  *)(mmio|MMIO_SB3500PSDA_EN);
      status = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_STATUS);
      break;
    case PSD_B:
      d2a = (volatile unsigned *)(mmio|MMIO_SB3500D2A_B_OFF);
      en  = (volatile unsigned  *)(mmio|MMIO_SB3500PSDB_EN);
      status = (volatile unsigned *)(mmio|MMIO_SB3500PSDB_STATUS);
      break;
    default:
      return;
  }
  d2a[6]     = 0;         /* Clear Control register */
  en[0]      = 0;         /* Disable D2A interrupt */
  status[0]  = 1;         /* Disable D2A interrupt */
}

int psd_is_interrupt_dtoa(unsigned int psd) {
  unsigned gifr = __sb_cfsr(MACH_GIFR);
  unsigned bit;
  switch (psd) {
    case PSD_A:
      bit = gifr>>MMIO_SB3500PSDA_INT;
      break;
    case PSD_B:
      bit = gifr>>MMIO_SB3500PSDB_INT;
      break;
    default:
      return 0;
  }
  return bit&0x1;
}

void psd_reset_interrupt_dtoa(unsigned int psd) {
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28)|MMIO_SB3500_BASE_ADDR;
  unsigned gifr_mask;
  volatile unsigned* status;
  switch (psd) {
    case PSD_A:
      gifr_mask = 1<<MMIO_SB3500PSDA_INT;
      status    = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_STATUS);
      break;
    case PSD_B:
      gifr_mask = 1<<MMIO_SB3500PSDB_INT;
      status    = (volatile unsigned *)(mmio|MMIO_SB3500PSDB_STATUS);
      break;
    default:
      return;
  }
  __sb_ctsr(gifr_mask, MACH_GIFR0);
  status[0] = 0x2;                /* enable D2A */
}

void psd_begin_atod(unsigned int psd, unsigned int dec, unsigned int buf_count, unsigned int buf_size, short *i, short *q) {
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28) | MMIO_SB3500_BASE_ADDR;
  unsigned control;
  volatile unsigned *a2d;
  volatile unsigned *en;
  switch (psd) {
    case PSD_A:
      a2d = (volatile unsigned *)(mmio|MMIO_SB3500A2D_A_OFF);
      en  = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_EN);
      break;
    case PSD_B:
      a2d = (volatile unsigned *)(mmio|MMIO_SB3500A2D_B_OFF);
      en  = (volatile unsigned *)(mmio|MMIO_SB3500PSDB_EN);
      break;
    default:
      break;
  }
  control = (0x3U<<30)            /* enable both I,Q */
            | ((dec&0x3)<<28)            /* Decimation control */
            | (((buf_count-1)&0xff)<<20)     /* buffers         */
            | ((0&0x3)<<18)              /* no PM timer        */
            | ((0&0x7)<<15)              /* no NMPT timer        */
            | ((buf_size-8)&0x7ff8);       /* bytes truncated to multiple of 8 */
  a2d[2] = (unsigned)i;       /* I start register */
  a2d[4] = (unsigned)q;       /* Q start register */
  a2d[6] = control;              /* Control register */
  en[0]  = 0x1;                  /* enable A2D Interrupt */
}

void psd_stop_atod(unsigned int psd) {
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28) | MMIO_SB3500_BASE_ADDR;
  volatile unsigned *a2d;
  volatile unsigned *en;
  volatile unsigned *status;
  switch (psd) {
    case PSD_A:
      a2d    = (volatile unsigned *)(mmio|MMIO_SB3500A2D_A_OFF);
      en     = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_EN);
      status = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_STATUS);
      break;
    case PSD_B:
      a2d    = (volatile unsigned *)(mmio|MMIO_SB3500A2D_B_OFF);
      en     = (volatile unsigned *)(mmio|MMIO_SB3500PSDB_EN);
      status = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_STATUS);
      break;
    default:
      return;
  }
  a2d[6]    = 0;              /* Clear Control register */
  en[0]     = 0;              /* disable A2D Interrupt */
  status[0] = 1;              /* clear A2D Interrupt flag */
}

int psd_is_interrupt_atod(unsigned int psd) {
  unsigned gifr = __sb_cfsr(MACH_GIFR);
  unsigned bit;
  switch (psd) {
    case PSD_A:
      bit = gifr>>MMIO_SB3500PSDA_INT;
      break;
    case PSD_B:
      bit = gifr>>MMIO_SB3500PSDB_INT;
      break;
    default:
      return 0;
  }
  return bit&0x1;
}

void psd_reset_interrupt_atod(unsigned int psd) {
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28)|MMIO_SB3500_BASE_ADDR;
  unsigned gifr_mask;
  volatile unsigned *status;
  switch (psd) {
    case PSD_A:
      gifr_mask = 1<<MMIO_SB3500PSDA_INT;
      status    = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_STATUS);
      break;
    case PSD_B:
      gifr_mask = 1<<MMIO_SB3500PSDB_INT;
      status    = (volatile unsigned *)(mmio|MMIO_SB3500PSDB_STATUS);
      break;
    default:
      return;
  }
  __sb_ctsr(gifr_mask, MACH_GIFR0);
  status[0] = 0x1;                /* clear A2D Interrupt flag */
}

void
stop_d2a(
  unsigned    channel    /* 0 = A, 1 = B      */
)
{
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28) | MMIO_SB3500_BASE_ADDR;
  volatile unsigned *d2a;
  volatile unsigned *en;
  volatile unsigned *status;

  if( channel == 0 ) {
    d2a    = (volatile unsigned *)(mmio|MMIO_SB3500D2A_A_OFF);
    en     = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_EN);
    status = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_STATUS);
  }
  else {
    d2a    = (volatile unsigned *)(mmio|MMIO_SB3500D2A_B_OFF);
    en     = (volatile unsigned *)(mmio|MMIO_SB3500PSDB_EN);
    status = (volatile unsigned *)(mmio|MMIO_SB3500PSDB_STATUS);
  }

  d2a[6]     = 0;         /* Clear Control register */
  en[0]      = 0;         /* Disable D2A interrupt */
  status[0]  = 1;         /* Disable D2A interrupt */
}

void
reset_interrupt_d2a(
  unsigned    channel    /* 0 = A, 1 = B */
)
{
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28)|MMIO_SB3500_BASE_ADDR;
  unsigned gifr_mask;
  volatile unsigned* status;

  if( channel == 0 ) {
    gifr_mask = 1<<MMIO_SB3500PSDA_INT;
    status    = (volatile unsigned *)(mmio|MMIO_SB3500PSDA_STATUS);
  }
  else {
    gifr_mask = 1<<MMIO_SB3500PSDB_INT;
    status    = (volatile unsigned *)(mmio|MMIO_SB3500PSDB_STATUS);
  }

  __sb_ctsr(gifr_mask, MACH_GIFR0);
  status[0] = 0x2;                /* enable D2A */
}

void
start_d2a(
  unsigned    channel,    /* 0 = A, 1 = B      */
  unsigned    nbufs,      /* number of buffers */
  unsigned    nbytes,     /* bytes/per buffer  */
  unsigned short*      ibuf,       /* data              */
  unsigned short*      qbuf
)
{
  unsigned core = (__sb_cfsr(MACH_THID)>>4)&0xf;
  unsigned mmio = (core<<28) | MMIO_SB3500_BASE_ADDR;
  unsigned control;
  volatile unsigned * d2a;
  volatile unsigned * en;

  if( channel == 0 ) {
    d2a = (volatile unsigned *)(mmio|MMIO_SB3500D2A_A_OFF);
    en  = (volatile unsigned  *)(mmio|MMIO_SB3500PSDA_EN);
  }
  else {
    d2a = (volatile unsigned *)(mmio|MMIO_SB3500D2A_B_OFF);
    en  = (volatile unsigned  *)(mmio|MMIO_SB3500PSDB_EN);
  }

  control = (3<<30)              /* enable both I,Q */
            | (1<<28)                    /* direction */
            | (((nbufs-1)&0xff)<<20)     /* buffers         */
            | ((0&0x3)<<18)              /* no PM timer        */
            | ((0&0x7)<<15)              /* no NMPT timer        */
            | ((nbytes-8)&0x7ff8);       /* bytes truncated to multiple of 8 */

  d2a[2] = (unsigned)ibuf;
  d2a[4] = (unsigned)qbuf;

  d2a[6] = control;
  en[0]  = 0x2;                   /* enable D2A */
}

int
is_interrupt_d2a(
  unsigned    channel
)
{
  unsigned gifr = __sb_cfsr(MACH_GIFR);
  unsigned bit  = (channel==0)?
                  gifr>>MMIO_SB3500PSDA_INT:
                  gifr>>MMIO_SB3500PSDB_INT;

  return bit&0x1;
}
